package models

import (
	"crypto/sha1"
	"fmt"
	"gitchina/kly_service/data"
	"gitchina/kly_service/errors"
	"gitchina/kly_service/util"
	"strings"
	_ "time"

	"sort"

	_ "github.com/astaxie/beego"
	_ "github.com/pborman/uuid"
)

type ChatRQ struct {
	SessionKey string `json:"session_key"`
	Offset     int64  `json:"offset"`
	Text       string `json:"text"`
	MessageId  string `json:"message_id"`
	TargetId   string `json:"target_id"`
}

type ChatLog struct {
	Id        int64  `json:"id"`
	Text      string `json:"text"`
	SenderId  string `json:"sender_id"`
	MessageId string `json:"message_id"`
	Time      string `json:"time"`
	MediaType int    `json:"media_type"`
}

type ChatLogListRS struct {
	TotalCount int       `json:"total_count"`
	List       []ChatLog `json:"chat_log_list"`
}

type GetChatLogListRQ struct {
	SessionKey string `json:"session_key"`
	PageNo     int    `json:"page_no"`
	PageSize   int    `json:"page_size"`
}

type GetChatContactsRQ struct {
	PageNo   int `json:"page_no"`
	PageSize int `json:"page_size"`
}

type SendMessageRQ struct {
	Text       string `json:"text"`
	SessionKey string `json:"session_key"`
	MediaType  int    `json:"media_type"`
}

type ByChartLogId []ChatLog

func (a ByChartLogId) Len() int           { return len(a) }
func (a ByChartLogId) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ByChartLogId) Less(i, j int) bool { return a[i].Id > a[j].Id }

type Social struct{}

func (s Social) CreateChatSession(mbrId, targetId string) (sessionKey string, err error) {
	var repo data.SocialRepo
	if strings.Compare(mbrId, targetId) < 0 {
		sessionKey = fmt.Sprintf("%x", sha1.Sum([]byte(fmt.Sprintf("%s%s", mbrId, targetId))))
	} else {
		sessionKey = fmt.Sprintf("%x", sha1.Sum([]byte(fmt.Sprintf("%s%s", targetId, mbrId))))
	}
	if err := repo.AddChatSession(sessionKey, []string{mbrId, targetId}); err != nil {
		util.GetLogger().Error("[model-CreateChatSession] - error:%s", err.Error())
	}
	return
}

func (s Social) AddChatLog(mbrId, sessionKey, text, messageId string, mediaType int) (id int64, err error) {
	var repo data.SocialRepo
	if id, err = repo.AddChatLog(sessionKey, text, mbrId, messageId, mediaType); err != nil {
		util.GetLogger().Error("[model-AddChatLog] - error:%s", err.Error())
	}
	return
}

func (s Social) SendMessage(from, fromName, sessionKey, text string, mediaType int) (err error) {
	var chatLogId int64
	var participants []string
	var repo data.SocialRepo

	if mediaType != 1 && mediaType != 2 {
		err = errors.New(errors.MSG_Social_Invalid_Message)
		return
	}

	callback := func(chatlogId int64, messageId string) error {
		return repo.SetMessageId(chatlogId, messageId)
	}
	if participants, err = repo.GetParticipants(sessionKey); err == nil {
		for _, p := range participants {
			if from != p {
				if chatLogId, err = s.AddChatLog(from, sessionKey, text, "", mediaType); err == nil {
					if mediaType == 1 {
						util.NewJMessageClient().SendTextMessage(from, p, fromName, text, chatLogId, callback)
					} else {
						util.NewJMessageClient().SendCustomMessage(from, p, fromName, text, mediaType, chatLogId, callback)
					}
				}
			}
		}
	} else {
		util.GetLogger().Error("[social.SendMessage] - error:%s", err.Error())
	}
	if err != nil {
		err = errors.New(errors.MSG_Social_Send_Message_Error)
	}
	return
}

func (s Social) GetChatLogs(sessionKey string, offset int64) (rs []ChatLog) {
	var repo data.SocialRepo
	if list, err := repo.GetChatLogs(sessionKey, offset); err == nil {
		rs = make([]ChatLog, len(list))
		for idx, dto := range list {
			rs[idx] = ChatLog{
				Id:        dto.Id,
				Text:      dto.Text,
				Time:      dto.Time,
				SenderId:  dto.SenderId,
				MessageId: dto.MessageId,
				MediaType: dto.MediaType,
			}
		}
	} else {
		util.GetLogger().Error("[model-GetChatLogs] - error:%s", err.Error())
	}
	return
}

func (c Social) GetLatestChatLogs(sessionKey string, pageNo, pageSize int) (rs ChatLogListRS) {
	var err error
	var count int64
	var list []ChatLog
	var chatLogs []data.ChatLogDto
	var repo data.SocialRepo
	if chatLogs, count, err = repo.GetLatestChatLogs(sessionKey, pageNo, pageSize); err == nil {
		list = make([]ChatLog, len(chatLogs))
		for i, chat := range chatLogs {
			list[i] = ChatLog{
				Id:        chat.Id,
				Text:      chat.Text,
				SenderId:  chat.SenderId,
				MessageId: chat.MessageId,
				Time:      chat.Time,
				MediaType: chat.MediaType,
			}
			if list[i].MediaType == 0 {
				list[i].MediaType = 1
			}
		}
		sort.Sort(ByChartLogId(list))
		rs = ChatLogListRS{TotalCount: int(count), List: list}
	} else {
		util.GetLogger().Error("[social.GetLatestChatLogs] - error:%s", err.Error())
	}
	return
}

func (s Social) GetChatContacts(mbrId string, pageNo, pageSize int) (rs []MemberBriefInfoRS) {
	var mId int64
	var mbrDtoList []data.MemberDto
	var repo data.SocialRepo
	if list, err := repo.GetChatSessions(mbrId, pageNo, pageSize); err == nil {
		ids := make([]int, 0)
		for _, session := range list {
			for _, id := range strings.Split(session.Participants, ",") {
				if mbrId != id {
					if _, _, _, mId, err = (ID(id)).Decode(); err == nil {
						ids = append(ids, int(mId))
					}
				}
			}
		}
		if len(ids) > 0 {
			var mbrRepo data.MemberRepo
			if mbrDtoList, err = mbrRepo.GetMemberBriefInfo(ids); err == nil {
				var memberId ID
				rs = make([]MemberBriefInfoRS, len(mbrDtoList))
				for i, m := range mbrDtoList {
					memberId.Encode(ID_Shard, ID_Ver, ID_Member_Category, int64(m.Id))
					rs[i] = MemberBriefInfoRS{
						Id:       memberId,
						Name:     m.Name,
						NickName: m.NickName,
						PhotoUrl: m.PhotoUrl,
					}
				}
			} else {
				util.GetLogger().Error("[model-GetContactHistory] - error:%s", err.Error())
			}
		}
	} else {
		util.GetLogger().Error("[model-GetChatSessions] - error:%s", err.Error())
	}
	return
}
